/*
 * mhdirscanner.cpp
 *
 *  Created on: 2010-8-24
 *      Author: angelstone
 */
#include <wx/wx.h>
#include <wx/dir.h>

#include "mhdirscanner.h"
#include "mhmedia.h"

using namespace mediahouse;

class CMHDirTraverserSimple: public wxDirTraverser {
public:
	CMHDirTraverserSimple(wxArrayString & files, wxArrayString & dirs);

	virtual wxDirTraverseResult OnFile(const wxString& filename);
	virtual wxDirTraverseResult OnDir(const wxString& dirname);

public:
	bool m_bDirOnly;
private:
	wxArrayString & m_Files;
	wxArrayString & m_Dirs;
};

int CMHDirScanner::CanScanPath(CMHContext * pContext,
		const wxString & strMediaPath, void * cookies) {
	return wxDirExists(strMediaPath) ? 1 : 0;
}

int CMHDirScanner::ScanPath(CMHContext * pContext,
		const wxString & strMediaPath, void * cookies) {
	wxArrayString files, dirs;
	size_t total_to_scan = 1;
	size_t item_scanned = 0;

	if (!CanScanPath(pContext, strMediaPath, cookies))
		return 0;

	CMHDirTraverserSimple traverser(files, dirs);

	dirs.Add(strMediaPath);

	wxString base_location = GetBaseLocation(pContext, strMediaPath);

	int value = 0;

	while(dirs.Count() > 0) {
		if (pContext->GetTaskThread() && pContext->GetTaskThread()->TestDestroy())
			return 1;

		if (pContext->Cancelled())
			return 1;

		wxString name = *dirs.begin();
		dirs.RemoveAt(0, 1);

		wxDir dir(name);

		traverser.m_bDirOnly = !ProcessDir(pContext, &dir, base_location);
		dir.Traverse(traverser);

		item_scanned++;

		total_to_scan = dirs.Count() + files.GetCount();

		if (!total_to_scan)
			total_to_scan = 1;

		pContext->NotifyTotalScanItems(total_to_scan, cookies);

		int new_value = 100 * item_scanned / total_to_scan;

		if (new_value >= 100)
			new_value = 99;

		if (new_value > value)
			value = new_value;

		pContext->NotifyItemScaned(value, cookies, name, false);
	}

	dirs.Clear();

	wxArrayString::iterator it;

	for (it = files.begin(); it != files.end(); it++) {
		if (pContext->GetTaskThread() && pContext->GetTaskThread()->TestDestroy())
			return 1;

		if (pContext->Cancelled())
			return 1;

		ProcessFile(pContext, cookies, *it, base_location);

		item_scanned++;

		int new_value = 100 * item_scanned / total_to_scan;

		if (new_value >= 100)
			new_value = 99;

		if (new_value > value)
			value = new_value;

		pContext->NotifyItemScaned(value, cookies, *it, false);
	}

	files.Clear();

	return 1;
}

CMHDirTraverserSimple::CMHDirTraverserSimple(wxArrayString & files,
		wxArrayString & dirs) :
	m_Files(files), m_Dirs(dirs) {
}

wxDirTraverseResult CMHDirTraverserSimple::OnFile(const wxString& filename) {
	if (m_Files.Index(filename) >= 0 || m_bDirOnly)
		return wxDIR_CONTINUE;

	m_Files.Add(filename);
	return wxDIR_CONTINUE;
}

wxDirTraverseResult CMHDirTraverserSimple::OnDir(const wxString& dirname) {
	if (m_Dirs.Index(dirname) >= 0)
		return wxDIR_CONTINUE;

	m_Dirs.Add(dirname);
	return wxDIR_CONTINUE;
}

int CMHDirScanner::ProcessDir(CMHContext * pContext,
		const wxDir * p_dir, const wxString & base_location) {
	hiberlite::bean_ptr<mediahouse::CMHMedia> dir;
	wxDateTime modifyTime(wxFileModificationTime(p_dir->GetName()));

	if (pContext->FindMediaByLocation(p_dir->GetName(), dir)) {
		if (dir->GetModified() >= modifyTime)
			return 0;
	} else {
		dir = pContext->GetDatabase()->createBean<mediahouse::CMHMedia> ();
		dir->SetLocation(p_dir->GetName());
		dir->SetProperty(wxT("directory"), wxT("true"));
		dir->SetProperty(wxT("base_location"), base_location);
	}

	dir->SetModified(modifyTime);
	dir.save();

	return 1;
}

int CMHDirScanner::ProcessFile(CMHContext * pContext, void * cookie,
		const wxString & file_path, const wxString & base_location) {
	hiberlite::bean_ptr<mediahouse::CMHMedia> media;
	wxDateTime modifyTime(wxFileModificationTime(file_path));

	if (pContext->FindMediaByLocation(file_path, media)) {
		if (media->GetModified() >= modifyTime)
			return 0;
	} else {
		media = pContext->GetDatabase()->createBean<mediahouse::CMHMedia> ();
		media->SetLocation(file_path);
		media->SetProperty(wxT("base_location"), base_location);
		media->SetProperty(wxT("file"), wxT("true"));
		media.save();
		//do not set modify time here
		//let the file scanner update modify time
	}

	return pContext->ScanItem(file_path, cookie);
}

wxString CMHDirScanner::GetBaseLocation(CMHContext * pContext, const wxString & path) {
	hiberlite::bean_ptr<mediahouse::CMHMedia> dir;

	if (pContext->FindMediaByLocation(path, dir)) {
		if (dir->HasProperty(wxT("base_location"))) {
			wxString value = wxEmptyString;
			if (!dir->GetProperty(wxT("base_location"), value))
				return value;
		}
	}

	return path;
}
